import { _decorator, Component, Node, Canvas, find, assetManager, AssetManager, instantiate, Asset } from 'cc';
import { GameApplication } from '../../Boot/GameApplication';
import { BaseTs } from '../../Prefabs/Scripts/BaseTs';
import { EventUtil } from './EventUtil';
import { EventConstant } from '../Constants/EventConstant';
const { ccclass, property } = _decorator;

@ccclass('UiUtil')
export class UiUtil extends Component {

    /**
     * 主场景的画布
     */
    canvas: Canvas = null;

    /**
     * 静态实例对象
     */
    public static INSTANCE: UiUtil = null;

    /**
     * 当前已经挂载的预制体
     */
    private uiMap: any[] = {};


    protected onLoad(): void {
        if (UiUtil.INSTANCE == null) {
            UiUtil.INSTANCE = this
        }
    }

    /**
     * 初始化场景
     */
    public init(canvas: Canvas) {

        // 初始化主场景的画布
        this.canvas = canvas
    }

    public showToast(msgBo: { msg: string, millisecond: number }) {

        this.createPrefabAsset('Prefabs', 'Toast', null, null, true, msgBo);
    }

    /**
     * 创建预制体
     * @param bundleName 预制体包的名称
     * @param prefabName 具体的预制体名称
     * @param assetType 预制体的类型
     * @param parent 挂载在哪个父类上
     */
    public createPrefabAsset(bundleName: string,
        prefabName: string,
        assetType,
        parent: any,
        loadScript: boolean,
        data: any) {

        // 判断是否是重复创建，如果是重复创建就需要将他进行销毁
        var prefabAsset = this.uiMap[prefabName];
        if (prefabAsset) {
            this.destroyPrefabAsset(prefabName);
        }

        var prefab = this.loadBundle(bundleName, prefabName, assetType);
        prefab.then(res => {
            this.mountPrefabAsset(parent, res, prefabName, loadScript, data)
        })
    }

    /**
     * 控制预制体
     * @param prefabName 预制体的名称
     * @param control true显示 false隐藏
     */
    public controlPrefabAsset(prefabName: string, control: boolean) {
        var prefabAsset = this.uiMap[prefabName];
        if (prefabAsset) {
            prefabAsset.active = control
        }
    }

    /**
     * 移除预制体
     * @param assetPath 预制体的名称
     */
    public removePrefabAsset(prefabName: string) {
        var prefabAsset = this.uiMap[prefabName];
        if (prefabAsset) {
            prefabAsset.removeFromParent();
            this.uiMap[prefabName] = null
        }
    }

    /**
     * 销毁预制体，释放资源（ 会释放内存，并且调用对应TS的destroy方法
     * @param prefabName 预制体的名称
     * @description
     * 调用一个节点的 removeFromParent 后，它不一定就能完全从内存中释放，因为有可能由于一些逻辑上的问题，导致程序中仍然引用到了这个对象。
     * 因此如果一个节点不再使用了，请直接调用它的 destroy 而不是 removeFromParent。
     * destroy 不但会激活组件上的 onDestroy，还会降低内存泄露的几率，同时减轻内存泄露时的后果。
     * 总之，如果一个节点不再使用，destroy 就对了，不需要 removeFromParent 也不需要设置 parent 为 null。
     */
    public destroyPrefabAsset(prefabName: string) {

        var prefabAsset = this.uiMap[prefabName];
        if (prefabAsset) {
            prefabAsset.destroy();
            this.uiMap[prefabName] = null
        }
    }

    /**
     * 
     * @param parent 挂载的场景，如果为空就会拿主场景挂载
     * @param asset 预制体资源
     * @param assetPath 预制体的名称
     * @param loadScript 是否加载指定脚本
     */
    public mountPrefabAsset(parent: any, asset: Asset, assetPath: string, loadScript: boolean,
        data: any) {

        parent = parent == null ? this.canvas.node : parent;
        var uiView = instantiate(asset);
        parent.addChild(uiView);
        this.uiMap[assetPath] = uiView;
        console.log('this.uiMap', this.uiMap);
        if (loadScript) {
            let ui = uiView.addComponent(assetPath + "Ts") as BaseTs;
            ui.init(data);
        }
    }

    /**
     * 加载预制体
     * @param bundleName 预制体包的名称
     * @param prefabName  具体的预制体名称
     * @param assetType  预制体的类型
     * @returns 
     */
    public async loadBundle(bundleName: string, prefabName: string, assetType) {
        var bundle: AssetManager.Bundle = assetManager.getBundle(bundleName);
        if (bundle === null) {
            bundle = await this.loadBundlePackage(bundleName) as any;
            if (bundle === null) {
                // console.log("bundle load err: " + bundleName);
                return;
            }
        }

        // 通过预制体包获取预制体资源数据（ 如果是第一次加载可能无法获取到 ）
        var assetData = bundle.get(prefabName);
        if (assetData) {
            return assetData; // 修改了没有返回资源的bug
        }

        assetData = await this.loadBundleAsset(bundle, prefabName, assetType) as any;
        return assetData;
    }

    /**
     * 加载预制体包
     * @param bundleName 预制体包名称
     * @returns 
     */
    private async loadBundlePackage(bundleName: string) {
        return new Promise((resolve, reject) => {
            assetManager.loadBundle(bundleName, (err, bundleData) => {
                if (err) {
                    console.log(err);
                    reject(null);
                    return;
                }
                else {
                    resolve(bundleData);
                    return;
                }
            })
        });
    }

    /**
     * 从预制体包中加载预制体资源信息
     * @param bundle    预制体包对象
     * @param assetName     预制体名称
     * @param assetType 类型
     * @returns 
     */
    private async loadBundleAsset(bundle: AssetManager.Bundle, assetName: string, assetType) {
        return new Promise((resolve, reject) => {
            bundle.load(assetName, assetType, (err, assetData) => {
                if (err) {
                    reject(err);
                    return;
                }
                else {
                    resolve(assetData);
                }
            });
        });
    }
}

